package com.leyou.order.service;

import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exceptions.LyException;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.IdWorker;
import com.leyou.item.client.ItemClient;
import com.leyou.item.dto.SkuDTO;
import com.leyou.order.dto.CartDTO;
import com.leyou.order.dto.OrderDTO;
import com.leyou.order.entity.Order;
import com.leyou.order.entity.OrderDetail;
import com.leyou.order.entity.OrderLogistics;
import com.leyou.order.enums.OrderStatusEnum;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderLogisticsMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.utils.PayHelper;
import com.leyou.order.utils.UserHolder;
import com.leyou.order.vo.OrderDetailVO;
import com.leyou.order.vo.OrderLogisticsVO;
import com.leyou.order.vo.OrderVO;
import com.leyou.user.client.UserClient;
import com.leyou.user.dto.AddressDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 虎哥
 */
@Slf4j
@Service
public class OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderDetailMapper detailMapper;

    @Autowired
    private OrderLogisticsMapper logisticsMapper;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private ItemClient itemClient;

    @Autowired
    private UserClient userClient;

    @Transactional
    public Long createOrder(OrderDTO orderDTO) {

        // 1.新增订单数据
        Order order = new Order();
        // 1.1.订单编号
        long orderId = idWorker.nextId();
        order.setOrderId(orderId);
        // 1.2.订单金额相关
        List<CartDTO> carts = orderDTO.getCarts();
        // 1.2.1.获取价格和id的映射关系
        Map<Long, Integer> skuMap = carts.stream()
                .collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));
        // 1.2.2.获取订单中的商品的id
        List<Long> idList = carts.stream().map(CartDTO::getSkuId).collect(Collectors.toList());
        // 1.2.3.根据id查询商品
        List<SkuDTO> skuList = itemClient.querySkuByIds(idList);
        // 准备detail的集合
        List<OrderDetail> detailList = new ArrayList<>();
        // 1.2.4.计算总金额
        long total = 0;
        for (SkuDTO skuDTO : skuList) {
            // 计算总金额
            Integer num = skuMap.get(skuDTO.getId());
            total += skuDTO.getPrice() * num;
            // 把sku数据封装到OrderDetail
            OrderDetail detail = new OrderDetail();
            detail.setTitle(skuDTO.getTitle());
            detail.setSkuId(skuDTO.getId());
            detail.setPrice(skuDTO.getPrice());
            detail.setNum(num);
            detail.setOwnSpec(skuDTO.getOwnSpec());
            detail.setImage(StringUtils.substringBefore(skuDTO.getImages(), ","));
            detail.setOrderId(orderId);
            detailList.add(detail);
        }
        // 1.2.5.封装
        order.setTotalFee(total);
        order.setPostFee(0L);
        order.setActualFee(total + order.getPostFee());
        order.setPaymentType(orderDTO.getPaymentType());
        // 1.3.订单用户信息
        Long userId = UserHolder.getUser().getId();
        order.setUserId(userId);
        // 1.4.订单状态信息
        order.setStatus(OrderStatusEnum.INIT.value());
        orderMapper.insertSelective(order);

        // 2.新增订单详情
        detailMapper.insertList(detailList);

        // 3.新增订单物流
        Long addressId = orderDTO.getAddressId();
        // 3.1.根据地址的id查询地址
        AddressDTO addressDTO = userClient.queryAddressById(userId, addressId);
        // 3.2.把地址封装OrderLogistics对象
        OrderLogistics logistics = BeanHelper.copyProperties(addressDTO, OrderLogistics.class);
        logistics.setOrderId(orderId);
        // 3.3.写入数据库
        logisticsMapper.insertSelective(logistics);

        // 4.减库存
        try {
            itemClient.minusStock(skuMap);
        } catch (Exception e) {
            throw new LyException(ExceptionEnum.STOCK_NOT_ENOUGH);
        }

        return orderId;
    }

    public OrderVO queryOrderById(Long orderId) {
        // 查询订单
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (order == null) {
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        OrderVO orderVO = BeanHelper.copyProperties(order, OrderVO.class);

        // 查询订单物流
        orderVO.setLogistics(queryLogisticsByOrderId(orderId));

        // 查询订单详情
        orderVO.setDetailList(queryDetailByOrderId(orderId));

        return orderVO;
    }

    private List<OrderDetailVO> queryDetailByOrderId(Long orderId) {
        OrderDetail detail = new OrderDetail();
        detail.setOrderId(orderId);
        List<OrderDetail> list = detailMapper.select(detail);
        if (CollectionUtils.isEmpty(list)) {
            throw new LyException(ExceptionEnum.ORDER_DETAIL_NOT_FOUND);
        }
        return BeanHelper.copyWithCollection(list, OrderDetailVO.class);
    }

    private OrderLogisticsVO queryLogisticsByOrderId(Long orderId) {
        OrderLogistics logistics = logisticsMapper.selectByPrimaryKey(orderId);
        if (logistics == null) {
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        return BeanHelper.copyProperties(logistics, OrderLogisticsVO.class);
    }

    @Autowired
    private PayHelper payHelper;

    public String getPayUrl(Long orderId) {
        // 查询订单
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (order == null) {
            // 订单编号错误，抛出400
            throw new LyException(ExceptionEnum.INVALID_PARAM_ERROR);
        }
        // 判断订单是否已经支付，如果已经支付，就无需查询了
        if (!Objects.equals(order.getStatus(), OrderStatusEnum.INIT.value())) {
            // 订单状态不正确，已经支付了。
            throw new LyException(ExceptionEnum.INVALID_ORDER_STATUS);
        }
        // 获取金额
        Long actualFee = order.getActualFee();
        // 调用工具类，获取支付的地址
        return payHelper.getPayUrl(orderId, actualFee, "乐优商城商品");
    }

    public void handleNotify(Map<String, String> data) {
        try {
            // 验证签名
            payHelper.checkSignature(data);
            // 订单状态校验（保证幂等，防止重复通知）
            String outTradeNo = data.get("out_trade_no");
            String totalFee = data.get("total_fee");
            if (StringUtils.isBlank(outTradeNo) || StringUtils.isBlank(totalFee)) {
                // 数据有误
                throw new RuntimeException("订单编号或订单金额为空！");
            }
            Long orderId = Long.valueOf(outTradeNo);
            Order order = orderMapper.selectByPrimaryKey(orderId);
            if (!order.getStatus().equals(OrderStatusEnum.INIT.value())) {
                // 说明订单已经支付过了，属于重复通知，直接返回
                return;
            }
            // 订单金额校验
            Long total = Long.valueOf(totalFee);
            if (!total.equals(order.getActualFee())) {
                throw new RuntimeException("订单金额有误，我要报警了！");
            }

            // 修改订单的状态为已支付
            order = new Order();
            order.setOrderId(orderId);
            order.setStatus(OrderStatusEnum.PAY_UP.value());
            order.setPayTime(new Date());

            orderMapper.updateByPrimaryKeySelective(order);

            log.info("订单支付通知处理成功！订单编号:{}", orderId);
        } catch (RuntimeException e) {
            log.error("订单支付失败！{}", e.getMessage());
            throw new RuntimeException(e);
        }

    }

    @Transactional
    public void evictUnpaidOrder(Date deadLine) {
        // 1.查询超时未支付订单
        List<Long> idList = orderMapper.queryOverdueUnpaidOrder(deadLine);

        // 2.修改订单状态为已关闭
        Order order = new Order();
        order.setStatus(OrderStatusEnum.CLOSED.value());
        order.setCloseTime(new Date());
        Example example = new Example(Order.class);
        example.createCriteria().andIn("orderId", idList);
        orderMapper.updateByExampleSelective(order, example);

        // 3.查询订单关联的商品及购买的数量
        Example example1 = new Example(OrderDetail.class);
        example1.createCriteria().andIn("orderId", idList);
        List<OrderDetail> detailList = detailMapper.selectByExample(example1);

        // 获取sku及数量
        Map<Long, Integer> skuMap = detailList.stream()
                .collect(Collectors.groupingBy(OrderDetail::getSkuId, Collectors.summingInt(OrderDetail::getNum)));

        // 4.恢复库存
        try {
            itemClient.plusStock(skuMap);
        } catch (Exception e) {
            throw new RuntimeException("恢复库存失败！", e);
        }
    }
}
